Skip to content

🤖 fix: accept description as alias for display_name in bash tool#3247

Merged
ammario merged 1 commit intomainfrom
bash-tool-h76v
May 7, 2026
Merged

🤖 fix: accept description as alias for display_name in bash tool#3247
ammario merged 1 commit intomainfrom
bash-tool-h76v

Conversation

@ammar-agent
Copy link
Copy Markdown
Collaborator

Summary

DeepSeek V4 emits description instead of display_name for the bash tool, causing every bash invocation to fail validation. Normalize description as an undocumented alias for display_name in the schema preprocess so calls validate without changing the public tool surface.

Background

The bash tool requires display_name for every invocation. DeepSeek V4 reliably emits description instead, so we add an alias mirroring the existing commandscript normalization. The alias is intentionally undocumented in the tool description: we don't want to invite other models to use the wrong field.

Implementation

Refactored the bash schema's preprocess from a single if/else if/else chain into chained mutations on a local obj reference, so multiple normalizations can compose:

  1. commandscript (existing).
  2. descriptiondisplay_name (new, with a comment noting DeepSeek V4 as the reason).

Canonical fields always win when both are provided, mirroring the existing command/script precedence.

Validation

  • New unit tests in toolDefinitions.test.ts cover the alias and the precedence behavior.
  • bun test src/common/utils/tools/toolDefinitions.test.ts: 36 pass.
  • make static-check: passed locally.

Generated with mux • Model: anthropic:claude-opus-4-7 • Thinking: max • Cost: $0.62

DeepSeek V4 emits 'description' instead of 'display_name' for the bash
tool. Normalize the alias in the schema preprocess so the call still
validates without exposing the alias in the public tool description.
@ammar-agent
Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ammario ammario merged commit 97e99a5 into main May 7, 2026
40 of 42 checks passed
@ammario ammario deleted the bash-tool-h76v branch May 7, 2026 15:20
mux-bot Bot added a commit that referenced this pull request May 7, 2026
The bash tool's z.preprocess shim normalizes quirky model emissions to
canonical field names. After the DeepSeek v4 fix in #3247 added a second
'description' → 'display_name' rename block (mirroring the existing
'command' → 'script' rename), the two blocks were structurally identical:
skip when canonical is already a string, drop the alias via destructure,
re-spread with the canonical name. Each alias still required its own
'as Record<string, unknown> & { <alias>: string }' cast plus the same
three-line destructure/spread.

Extract a private renameAliasField(obj, alias, canonical) helper that
captures the rename pattern in one place, with the rationale for why
aliases exist (and why they stay undocumented) noted on the helper. The
call site collapses to two named lines that read as the intent
('rename command to script', 'rename description to display_name')
instead of fifteen lines of mostly-identical destructure/spread.

Pure refactor — emitted JS, the canonical-field-wins precedence, the
'no-op when neither alias nor canonical is a string' branches, and the
existing 36-test toolDefinitions suite (including the four new
command/description alias precedence cases) are all unchanged.
@mux-bot mux-bot Bot mentioned this pull request May 7, 2026
mux-bot Bot added a commit that referenced this pull request May 7, 2026
The bash tool's z.preprocess shim normalizes quirky model emissions to
canonical field names. After the DeepSeek v4 fix in #3247 added a second
'description' → 'display_name' rename block (mirroring the existing
'command' → 'script' rename), the two blocks were structurally identical:
skip when canonical is already a string, drop the alias via destructure,
re-spread with the canonical name. Each alias still required its own
'as Record<string, unknown> & { <alias>: string }' cast plus the same
three-line destructure/spread.

Extract a private renameAliasField(obj, alias, canonical) helper that
captures the rename pattern in one place, with the rationale for why
aliases exist (and why they stay undocumented) noted on the helper. The
call site collapses to two named lines that read as the intent
('rename command to script', 'rename description to display_name')
instead of fifteen lines of mostly-identical destructure/spread.

Pure refactor — emitted JS, the canonical-field-wins precedence, the
'no-op when neither alias nor canonical is a string' branches, and the
existing 36-test toolDefinitions suite (including the four new
command/description alias precedence cases) are all unchanged.
mux-bot Bot added a commit that referenced this pull request May 9, 2026
The bash tool's z.preprocess shim normalizes quirky model emissions to
canonical field names. After the DeepSeek v4 fix in #3247 added a second
'description' → 'display_name' rename block (mirroring the existing
'command' → 'script' rename), the two blocks were structurally identical:
skip when canonical is already a string, drop the alias via destructure,
re-spread with the canonical name. Each alias still required its own
'as Record<string, unknown> & { <alias>: string }' cast plus the same
three-line destructure/spread.

Extract a private renameAliasField(obj, alias, canonical) helper that
captures the rename pattern in one place, with the rationale for why
aliases exist (and why they stay undocumented) noted on the helper. The
call site collapses to two named lines that read as the intent
('rename command to script', 'rename description to display_name')
instead of fifteen lines of mostly-identical destructure/spread.

Pure refactor — emitted JS, the canonical-field-wins precedence, the
'no-op when neither alias nor canonical is a string' branches, and the
existing 36-test toolDefinitions suite (including the four new
command/description alias precedence cases) are all unchanged.
mux-bot Bot added a commit that referenced this pull request May 10, 2026
The bash tool's z.preprocess shim normalizes quirky model emissions to
canonical field names. After the DeepSeek v4 fix in #3247 added a second
'description' → 'display_name' rename block (mirroring the existing
'command' → 'script' rename), the two blocks were structurally identical:
skip when canonical is already a string, drop the alias via destructure,
re-spread with the canonical name. Each alias still required its own
'as Record<string, unknown> & { <alias>: string }' cast plus the same
three-line destructure/spread.

Extract a private renameAliasField(obj, alias, canonical) helper that
captures the rename pattern in one place, with the rationale for why
aliases exist (and why they stay undocumented) noted on the helper. The
call site collapses to two named lines that read as the intent
('rename command to script', 'rename description to display_name')
instead of fifteen lines of mostly-identical destructure/spread.

Pure refactor — emitted JS, the canonical-field-wins precedence, the
'no-op when neither alias nor canonical is a string' branches, and the
existing 36-test toolDefinitions suite (including the four new
command/description alias precedence cases) are all unchanged.
mux-bot Bot added a commit that referenced this pull request May 10, 2026
The bash tool's z.preprocess shim normalizes quirky model emissions to
canonical field names. After the DeepSeek v4 fix in #3247 added a second
'description' → 'display_name' rename block (mirroring the existing
'command' → 'script' rename), the two blocks were structurally identical:
skip when canonical is already a string, drop the alias via destructure,
re-spread with the canonical name. Each alias still required its own
'as Record<string, unknown> & { <alias>: string }' cast plus the same
three-line destructure/spread.

Extract a private renameAliasField(obj, alias, canonical) helper that
captures the rename pattern in one place, with the rationale for why
aliases exist (and why they stay undocumented) noted on the helper. The
call site collapses to two named lines that read as the intent
('rename command to script', 'rename description to display_name')
instead of fifteen lines of mostly-identical destructure/spread.

Pure refactor — emitted JS, the canonical-field-wins precedence, the
'no-op when neither alias nor canonical is a string' branches, and the
existing 36-test toolDefinitions suite (including the four new
command/description alias precedence cases) are all unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants